/**
 * File: FastSequenceExtract.java
 * Created by: mhaimel
 * Created on: Aug 4, 2011
 * CVS:  $Id: FastSequenceExtract.java 1.0 Aug 4, 2011 11:07:34 AM mhaimel Exp $
 */
package uk.ac.ebi.curtain.exec;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import uk.ac.ebi.curtain.storage.sequence.fast.FastBlockReader;
import uk.ac.ebi.curtain.utils.Pair;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;
import uk.co.flamingpenguin.jewel.cli.ArgumentValidationException;
import uk.co.flamingpenguin.jewel.cli.Cli;
import uk.co.flamingpenguin.jewel.cli.CliFactory;
import uk.co.flamingpenguin.jewel.cli.Option;

/**
 * @author mhaimel
 *
 */
public class FastSequenceExtract implements Closeable{
	private static interface Fse {

		@Option(shortName = "c",description="contig index file")
		public File getContigIndexFile();

		@Option(shortName = "f",description="Fast Sequence database file")
		public File getFastDbFile();
		
		@Option(shortName = "q",description="Query id e.g. this-is-my-contig-sequence-id-23432")
		public String getQueryId();
		
		@Option(shortName = "a", description="TRUE, if you are quering with ARC identifiers")
		public Boolean getArcType();
		
		@Option(helpRequest = true, description = "display helpfull menu", shortName = "h")
		boolean getHelp();
	}

	private final FastBlockReader fbr;
	private File ctgIdx;
	
	public FastSequenceExtract(File ctgIdx, File fdb) {
		this.ctgIdx = ctgIdx;
		this.fbr = new FastBlockReader(fdb);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Fse param = null;
		Cli<Fse> cli = CliFactory.createCli(Fse.class);
		try {
			param = cli.parseArguments(args);
		} catch (ArgumentValidationException e1) {
			System.err.println(e1.getMessage());
			System.exit(1);
		}
		File ctgIdx = param.getContigIndexFile();
		File fdb = param.getFastDbFile();
		String query = param.getQueryId();
		try {
			if(!ctgIdx.exists()) throw new FileNotFoundException("File does not exist: " + ctgIdx);
			if(!fdb.exists()) throw new FileNotFoundException("File does not exist: " + ctgIdx);
			if(query.isEmpty()) throw new IOException("Query sting is empty");
		} catch (IOException e) {
			System.err.println("----------------");
			System.err.println(e.getMessage());
			System.err.println("----------------");
			System.err.print(cli.getHelpMessage());
			System.exit(1);
		}
		
		FastSequenceExtract fse = new FastSequenceExtract(ctgIdx, fdb);
		try{
			fse.open();
			if(param.getArcType()){
				fse.queryArc(Long.valueOf(query),System.out);
			}else {
				fse.query(query,System.out);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			FileIO.closeQuietly(fse);
		}

	}

	public void queryArc(Long arcId, PrintStream out) {
		List<Pair<String, Long>> qList = new ArrayList<Pair<String,Long>>();
		qList.add(new Pair<String, Long>(arcId.toString(), arcId));
		_doQuery(qList,out);
	}

	public void query(String query, PrintStream out) throws IOException {
		List<Pair<String, Long>> qList = prepareQuery(query);
		_doQuery(qList,out);
	}

	private void _doQuery(List<Pair<String, Long>> qList, PrintStream out) {
		for(Pair<String, Long> q : qList){
			String id = q.getA();
			Iterable<String> entries = fbr.getEntries(q.getB());
			for(String s : entries){
				out.print(id);
				out.print("\t");
				out.println(s);
			}
		}
	}

	private List<Pair<String, Long>> prepareQuery(String query) throws IOException {
		Set<String> queries = new HashSet<String>();
		queries.add(query);
		return prepareQuery(queries);
	}
	private List<Pair<String, Long>> prepareQuery(Set<String> queries) throws IOException {
		List<Pair<String, Long>> list = new LinkedList<Pair<String,Long>>();
		BufferedReader br = null;
		try {
			br = new FileIO(this.ctgIdx).getBufferedReader();
			String s = null;
			while((s = br.readLine()) != null){
				s = s.trim();
				if(!s.isEmpty()){
					String[] arr = s.split("\t");
					if(queries.contains(arr[1])){
						list.add(new Pair<String, Long>(arr[1], Long.valueOf(arr[0])));
					}
				}
			}
		} finally{
			FileIO.closeQuietly(br);
		}
		return list;
	}
	public void open() throws IOException{
		this.fbr.open();
	}

	@Override
	public void close() throws IOException {
		this.fbr.close();
	}
}
